package com.onlyxiahui.common.lib.util.http;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;

/**
 * 
 * <br>
 * Date 2020-06-18 15:18:57<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class HttpClientPoolingAdaptor extends HttpClientAdaptor {

	private static final int DEFAULT_POOL_MAX_TOTAL = 200;
	private static final int DEFAULT_POOL_MAX_PER_ROUTE = 200;

	private static final int DEFAULT_CONNECT_TIMEOUT = 500;
	private static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 500;
	private static final int DEFAULT_SOCKET_TIMEOUT = 2000;

	private PoolingHttpClientConnectionManager connectionManager = null;

	public final int statusCode = 200;

	/**
	 * 连接池的最大连接数
	 */
	private final int maxTotal;
	/**
	 * 连接池按route配置的最大连接数
	 */
	private final int maxPerRoute;

	/**
	 * tcp connect的超时时间
	 */
	private final int connectTimeout;
	/**
	 * 从连接池获取连接的超时时间
	 */
	private final int connectRequestTimeout;
	/**
	 * tcp io的读写超时时间
	 */
	private final int socketTimeout;

	private boolean trusted = true;

	public HttpClientPoolingAdaptor() {
		this(
				HttpClientPoolingAdaptor.DEFAULT_POOL_MAX_TOTAL,
				HttpClientPoolingAdaptor.DEFAULT_POOL_MAX_PER_ROUTE,
				HttpClientPoolingAdaptor.DEFAULT_CONNECT_TIMEOUT,
				HttpClientPoolingAdaptor.DEFAULT_CONNECT_REQUEST_TIMEOUT,
				HttpClientPoolingAdaptor.DEFAULT_SOCKET_TIMEOUT);

	}

	public HttpClientPoolingAdaptor(
			int maxTotal,
			int maxPerRoute,
			int connectTimeout,
			int connectRequestTimeout,
			int socketTimeout) {
		super(null);
		this.maxTotal = maxTotal;
		this.maxPerRoute = maxPerRoute;
		this.connectTimeout = connectTimeout;
		this.connectRequestTimeout = connectRequestTimeout;
		this.socketTimeout = socketTimeout;

		HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
			// retry handler
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				if (executionCount >= 3) {
					return false;
				}

				// 如果服务器断掉了连接那么重试
				if (exception instanceof NoHttpResponseException) {
					return true;
				}

				// 不重试握手异常
				if (exception instanceof SSLHandshakeException) {
					return false;
				}

				// IO传输中断重试
				if (exception instanceof InterruptedIOException) {
					return false;
				}

				// 未知服务器
				if (exception instanceof UnknownHostException) {
					return false;
				}

				// 超时就重试
				if (exception instanceof ConnectTimeoutException) {
					return false;
				}
				HttpClientContext clientContext = HttpClientContext.adapt(context);
				HttpRequest request = clientContext.getRequest();

				if (!(request instanceof HttpEntityEnclosingRequest)) {
					return true;
				}
				return false;
			}
		};
		SSLContextBuilder builder = new SSLContextBuilder();
		// 全部信任 不做身份鉴定
		try {
			builder.loadTrustMaterial(null, new TrustStrategy() {
				@Override
				public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
					return trusted;
				}
			});
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		}
		SSLContext sslc = null;
		try {
			sslc = builder.build();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslc, new String[] { "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2" }, null, NoopHostnameVerifier.INSTANCE);

		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("http", PlainConnectionSocketFactory.getSocketFactory())
				// .register("https", SSLConnectionSocketFactory.getSocketFactory())
				.register("https", sslsf)
				.build();

		PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
		// 最大连接数3000
		connectionManager.setMaxTotal(this.maxTotal);
		// 路由链接数400
		connectionManager.setDefaultMaxPerRoute(this.maxPerRoute);
		this.connectionManager = connectionManager;

		RequestConfig requestConfig = RequestConfig.custom()
				// 设置连接超时
				.setConnectTimeout(this.connectTimeout)
				// 设置读取超时
				.setSocketTimeout(this.socketTimeout)
				// 设置从连接池获取连接实例的超时
				.setConnectionRequestTimeout(this.connectRequestTimeout)
				.build();

		HttpClientBuilder httpClientBuilder = HttpClients.custom();
		custom(httpClientBuilder);
		CloseableHttpClient httpClient = httpClientBuilder
				.setConnectionManager(this.connectionManager)
				.setRetryHandler(httpRequestRetryHandler)
				.setDefaultRequestConfig(requestConfig)
				.evictIdleConnections(30, TimeUnit.SECONDS)
				.build();

		this.setHttpClient(httpClient);
//		private IdleConnectionMonitorThread idleThread = null;
//		idleThread = new IdleConnectionMonitorThread(this.connectionManager);
//		idleThread.start();

	}

	public void custom(HttpClientBuilder httpClientBuilder) {

	}

	public boolean isTrusted() {
		return trusted;
	}

	public void setTrusted(boolean trusted) {
		this.trusted = trusted;
	}

//	public void shutdown() {
//		idleThread.shutdown();
//	}

	// 监控有异常的链接
//	private class IdleConnectionMonitorThread extends Thread {
//
//		private final HttpClientConnectionManager manager;
//		private volatile boolean exitFlag = false;
//
//		public IdleConnectionMonitorThread(HttpClientConnectionManager manager) {
//			this.manager = manager;
//			setDaemon(true);
//		}
//
//		@Override
//		public void run() {
//			while (!this.exitFlag) {
//				synchronized (this) {
//					try {
//						this.wait(2000);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//				}
//				// 关闭失效的连接
//				manager.closeExpiredConnections();
//				// 可选的, 关闭30秒内不活动的连接
//				manager.closeIdleConnections(30, TimeUnit.SECONDS);
//			}
//		}
//
//		public void shutdown() {
//			this.exitFlag = true;
//			synchronized (this) {
//				notify();
//			}
//		}
//	}
}